#ifndef _L_SIMULATOR_111225_H
#define _L_SIMULATOR_111225_H

#include <lmacros.h>
#include <ltypes.h>
#include <lvectors.h>

#include <boost/shared_ptr.hpp>

LLIB_BEGIN;

/* The base class of simulator */
class Simulator {
public:
    virtual Boolean Initialize()    { return TRUE; }
    virtual Boolean Preprocess()    { return TRUE; }
    virtual Boolean Render()        = 0;
    virtual Boolean Finalize()      { return TRUE; }

    virtual Boolean OnKeyDown(Uint8 key, Int32 x, Int32 y, Uint8 modifiers)         { return TRUE; }
    virtual Boolean OnKeyUp(Uint8 key, Int32 x, Int32 y, Uint8 modifiers)           { return TRUE; }
    virtual Boolean OnSpecialKeyDown(Uint8 key, Int32 x, Int32 y, Uint8 modifiers)  { return TRUE; }
    virtual Boolean OnSpecialKeyUp(Uint8 key, Int32 x, Int32 y, Uint8 modifiers)    { return TRUE; }

    virtual Boolean OnMouseButtonDown(Uint8 button, Int32 x, Int32 y)               { return TRUE; }
    virtual Boolean OnMouseButtonUp(Uint8 button, Int32 x, Int32 y)                 { return TRUE; }
    virtual Boolean OnMouseMove(Uint8 button, Int32 x, Int32 y)                     { return TRUE; }
    virtual Boolean OnMouseWheel(Uint8 wheel, Int32 x, Int32 y)                     { return TRUE; }
};

/* The sub class of Simulator, proxy patten.
 * Implement the sence navigation using keyboard and mouse.
 */
class Navigator : public Simulator {
private:
    /* the original simulator */
    boost::shared_ptr<Simulator> pOriSim;
    /* the navigation stuff */
    geom::Vec3f _eye;
    geom::Vec3f _direction;
    const Float _eyeCenterDis;
    const Float _moveStep;
    geom::Vec2i _mouseDragStart;
    const Float _rotationRatio;
    geom::Vec3f _lastDirection;
    const Float _yDirectionMax;

public:
    /* Navigator proxy construction : get simulator by share pointer */
    Navigator(boost::shared_ptr<Simulator> simulator);
    /* Navigator proxy construction : get simulator by original pointer */
    Navigator(Simulator* simulator);

    /* Set eye position */
    void SetEyePosition(const geom::Vec3f& position) { _eye = position; }

    /* Unchanged methods */
    virtual Boolean Initialize()    { return pOriSim->Initialize(); }
    virtual Boolean Preprocess()    { return pOriSim->Preprocess(); }
    virtual Boolean Finalize()      { return pOriSim->Finalize(); }
    virtual Boolean OnKeyUp(Uint8 key, Int32 x, Int32 y, Uint8 modifiers)           { return pOriSim->OnKeyUp(key, x, y, modifiers); }
    virtual Boolean OnSpecialKeyUp(Uint8 key, Int32 x, Int32 y, Uint8 modifiers)    { return pOriSim->OnSpecialKeyUp(key, x, y, modifiers); }
    virtual Boolean OnMouseButtonUp(Uint8 button, Int32 x, Int32 y)                 { return pOriSim->OnMouseButtonUp(button, x, y); }
    virtual Boolean OnMouseWheel(Uint8 wheel, Int32 x, Int32 y)                     { return pOriSim->OnMouseWheel(wheel, x, y); }

    /* Proxy methods */
    virtual Boolean Render();
    virtual Boolean OnKeyDown(Uint8 key, Int32 x, Int32 y, Uint8 modifiers);
    virtual Boolean OnSpecialKeyDown(Uint8 key, Int32 x, Int32 y, Uint8 modifiers);
    virtual Boolean OnMouseButtonDown(Uint8 button, Int32 x, Int32 y);
    virtual Boolean OnMouseMove(Uint8 button, Int32 x, Int32 y);
};

LLIB_END;

#endif
